﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

using Weazel.Gezel.Model;
using Weazel.Gezel.Conversions.Model;

using GezelModel = Weazel.Gezel.Model.Model;

#endregion

namespace Weazel.Gezel.Conversions
{
  /// <summary>
  /// The ControllerConversionHelper class contains functionality
  /// to convert a Gezel controller of any type into a list of
  /// <see cref="ExecutionSet"/>'s.
  /// </summary>
  public static class ControllerConversionHelper
  {
    public static List<ExecutionSet> getControlSteps(
      SoftwareModel softwareModel, 
      Controller gezelController)
    {
      List<ExecutionSet> sfgExecutionSets = new List<ExecutionSet>();
      if (gezelController.Type == Controller.ControllerType.Hardwired)
      {
        string sfgName = gezelController.SignalFlowGraphRefs[0];
        SignalFlowGraph sfg = gezelController.SignalFlowGraphs[sfgName];
        ExecutionSet sfgExecutionSet = new ExecutionSet(softwareModel, 0, sfg);
        sfgExecutionSets.Add(sfgExecutionSet);

        return sfgExecutionSets;
      }
      else if (gezelController.Type == Controller.ControllerType.Sequencer)
      {
        int controlStep = 0;
        foreach (string sfgName in gezelController.SignalFlowGraphRefs)
        {
          ExecutionSet executionSet = 
            new ExecutionSet(
              softwareModel, 
              controlStep++, 
              gezelController.SignalFlowGraphs[sfgName]);
          sfgExecutionSets.Add(executionSet);
        }
        return sfgExecutionSets;
      }
      else if (gezelController.Type == Controller.ControllerType.Fsm)
      {
        int controlStep = 0;
        foreach (Transition transition in gezelController.Transitions.Values)
        {
          getControlStepsRecursive(
            softwareModel, 
            gezelController, 
            sfgExecutionSets, 
            ref controlStep, 
            transition
          );
        }
        return sfgExecutionSets;
      }
      else
        throw new ApplicationException(
          string.Format(
            "unsupported controller type: {0}", 
            gezelController.Type
          )
        );
    }

    /// <summary>
    /// Handles the controlsteps recursively for a
    /// finite state machine controller type
    /// </summary>
    /// <param name="gezelController"></param>
    /// <param name="sfgExecutionSets"></param>
    /// <param name="controlStep"></param>
    /// <param name="transition"></param>
    private static void getControlStepsRecursive(
      SoftwareModel softwareModel, 
      Controller gezelController, 
      List<ExecutionSet> sfgExecutionSets, 
      ref int controlStep, 
      Transition transition)
    {
      // handle the three different transition types separately
      if (transition.TransitionType == TransitionType.SimpleUnconditional)
      {
        ExecutionSet executionSet = new ExecutionSet(softwareModel, controlStep++);
        foreach (string sfgRef in transition.FirstTargetSfgs)
        {
          executionSet.Add(gezelController.SignalFlowGraphs[sfgRef]);
        }
        sfgExecutionSets.Add(executionSet);
      }
      else if (transition.TransitionType == TransitionType.SimpleConditional)
      {
        ExecutionSet firstExecutionSet = new ExecutionSet(softwareModel, controlStep++);
        foreach (string sfgRef in transition.FirstTargetSfgs)
        {
          firstExecutionSet.Add(gezelController.SignalFlowGraphs[sfgRef]);
        }
        sfgExecutionSets.Add(firstExecutionSet);

        ExecutionSet secondExecutionSet = new ExecutionSet(softwareModel, controlStep++);
        foreach (string sfgRef in transition.SecondTargetSfgs)
        {
          secondExecutionSet.Add(gezelController.SignalFlowGraphs[sfgRef]);
        }
        sfgExecutionSets.Add(secondExecutionSet);
      }
      else if (transition.TransitionType == TransitionType.Nested)
      {
        if (transition.FirstTransition.TransitionType == TransitionType.SimpleUnconditional)
        {
          ExecutionSet executionSet = new ExecutionSet(softwareModel, controlStep++);
          foreach (string sfgRef in transition.FirstTransition.FirstTargetSfgs)
          {
            executionSet.Add(gezelController.SignalFlowGraphs[sfgRef]);
          }
          sfgExecutionSets.Add(executionSet);
        }
        else
        {
          // recurse
          getControlStepsRecursive(softwareModel, gezelController, sfgExecutionSets, ref controlStep, transition.FirstTransition);
        }

        // recurse
        getControlStepsRecursive(softwareModel, gezelController, sfgExecutionSets, ref controlStep, transition.SecondTransition);
      }
      else
        // should never happen
        throw new ApplicationException("unsupported fsm-transition type");
    }
  }
}
